package com.github.io.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.io.entity.*;
import com.github.io.enums.RequestMethodEnum;
import com.github.io.mapper.*;
import com.github.io.service.ISbApiDataService;
import com.github.io.service.ISbApiResultExplanationDataService;
import okhttp3.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liry
 * @version 1.0
 * @date Created on 2022/9/14 9:23
 * Description:
 */
@Service("dataService")
public class SbApiDataServiceImpl extends ServiceImpl<SbApiDataMapper, SbApiData> implements ISbApiDataService {

    @Autowired
    private SbApiDataMapper apiDataMapper;

    @Autowired
    private SbApiHeaderDataMapper headerDataMapper;

    @Autowired
    private SbApiQueryDataMapper queryDataMapper;

    @Autowired
    private SbApiBodyDataMapper bodyDataMapper;

    @Autowired
    private SbApiBodyKvDataMapper bodyKvDataMapper;
    
    @Autowired
    private SbApiResultExplanationDataMapper resultExplanationDataMapper;
    
    @Autowired
    private SbApiPathVariableDataMapper pathVariableDataMapper;

    @Autowired
    private ISbApiResultExplanationDataService resultExplanationDataService;


    @Override
    public int saveApiData(SbApiData sbApiData) {
        int count = apiDataMapper.insert(sbApiData);
        insertApiInfo(sbApiData);
        return count;
    }

    @Override
    public int updateApiData(SbApiData sbApiData) {
        int count = apiDataMapper.updateById(sbApiData);
        deleteApi(sbApiData.getId());
        insertApiInfo(sbApiData);
        return count;
    }

    @Override
    public SbApiData getApiInfo(String apiId) {
        SbApiData apiData = apiDataMapper.selectById(apiId);
        if (ObjectUtils.isEmpty(apiData)) return null;

        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("api_id", apiId);
        List<SbApiHeaderData> sbApiHeaderDatas = headerDataMapper.selectByMap(paramMap);
        List<SbApiQueryData> sbApiQueryDatas = queryDataMapper.selectByMap(paramMap);
        List<SbApiBodyData> sbApiBodyDatas = bodyDataMapper.selectByMap(paramMap);
        List<SbApiResultExplanationData> resultExplanationDataList = resultExplanationDataService.selectTree(apiId);
        List<SbApiPathVariableData> sbApiPathVariableDataList = pathVariableDataMapper.selectByMap(paramMap);
        SbApiBodyData sbApiBodyData = null;
        if (!CollectionUtils.isEmpty(sbApiBodyDatas)) {
            sbApiBodyData = sbApiBodyDatas.get(0);
            // 获取 body kv数据
            if (sbApiBodyData.getType() == 1) {
                String bodyId = sbApiBodyData.getId();
                QueryWrapper<SbApiBodyKvData> sbApiBodyKvDataQueryWrapper = new QueryWrapper<>();
                sbApiBodyKvDataQueryWrapper.eq("body_id", bodyId);
                List<SbApiBodyKvData> apiBodyKvDatas = bodyKvDataMapper.selectList(sbApiBodyKvDataQueryWrapper);
                sbApiBodyData.setBodyKvDataList(apiBodyKvDatas);
            }
        }

        apiData.setHeaderDataList(sbApiHeaderDatas);
        apiData.setQueryDataList(sbApiQueryDatas);
        apiData.setBodyData(sbApiBodyData);
        apiData.setPathVariableDataList(sbApiPathVariableDataList);
        apiData.setResultExplanationDataList(resultExplanationDataList);
        return apiData;
    }

    @Override
    public Object execute(String apiId) throws IOException {
        InputStream inputStream = null;
        try {
            SbApiData apiInfo = getApiInfo(apiId);
            if (ObjectUtils.isEmpty(apiInfo)) return null;

            // 创建连接对象
            OkHttpClient client = new OkHttpClient.Builder().build();
            Request.Builder requestBuilder = new Request.Builder();

            StringBuilder urlBuilder = new StringBuilder();
            urlBuilder
                    .append(apiInfo.getRemoteIp())
                    .append(":")
                    .append(apiInfo.getPort())
                    .append(apiInfo.getUrl());
            
            // 获取请求路径上参数
            List<SbApiPathVariableData> pathVariableDataList = apiInfo.getPathVariableDataList();
            pathVariableDataList.forEach(v->{
                String pathVariable;
                if ( !ObjectUtils.isEmpty(pathVariable = v.getPathVariable())){
                    pathVariable = StringUtils.trimWhitespace(pathVariable);
                    urlBuilder
                            .append("/")
                            .append(pathVariable);
                }
            });

            // 封装请求参数
            List<SbApiQueryData> queryDataList = apiInfo.getQueryDataList();
            if (!CollectionUtils.isEmpty(queryDataList)) {
                urlBuilder.append("?");
                queryDataList.forEach(v -> {
                    urlBuilder
                            .append(v.getQueryKey())
                            .append("=")
                            .append(v.getQueryValue())
                            .append("&");
                });
                urlBuilder.deleteCharAt(urlBuilder.length() - 1);
            }


            // 获取请求头
            List<SbApiHeaderData> headerDataList = apiInfo.getHeaderDataList();
            if (!CollectionUtils.isEmpty(headerDataList)) {
                headerDataList.forEach(v -> {
                    String headerKey = v.getHeaderKey();
                    String headerValue = v.getHeaderValue();
                    requestBuilder.addHeader(headerKey, headerValue);
                });
            }

            // 1 GET、2 POST、3 PUT、4 DELETE
            String methodType = apiInfo.getMethodType();
            String methodTypeValue = RequestMethodEnum.getRequestMethodEnum(methodType).getValue();

            // 封装请求体
            SbApiBodyData bodyData = apiInfo.getBodyData();
            RequestBody body = null;
            if (!ObjectUtils.isEmpty(bodyData)) {
                int type = bodyData.getType();
                if (type == 1) {
                    // 组装 kv参数
                    List<SbApiBodyKvData> bodyKvDataList = bodyData.getBodyKvDataList();
                    MultipartBody.Builder multipartBodyBuilder =
                            new MultipartBody
                                    .Builder()
                                    .setType(MultipartBody.FORM);
                    if (!CollectionUtils.isEmpty(bodyKvDataList)) {
                        bodyKvDataList.forEach(v -> {
                            multipartBodyBuilder.addFormDataPart(v.getBodyKey(), v.getBodyValue());
                        });
                    }
                    body = multipartBodyBuilder.build();
                } else if (type == 2) {
                    String jsonValue = bodyData.getJsonValue();
                    body = RequestBody.create(MediaType.parse("application/json"), jsonValue);
                }
            }

            Request request = requestBuilder
                    .url(urlBuilder.toString())
                    .method(methodTypeValue, body)
                    .build();

            // 发送请求
            Response execute = client.newCall(request).execute();
            ResponseBody responseBody = execute.body();
            inputStream = responseBody.byteStream();
            StringBuilder resultData = new StringBuilder();
            int length;
            byte[] by=new byte[1024];
            while ((length = inputStream.read(by)) != -1){
                resultData.append(new String(by, 0, length));
            }
            
            inputStream.close();
            System.out.println("-------------------------------");
            String responseData = resultData.toString();
            JSONObject responseJsonData = JSONObject.parseObject(responseData);
            System.out.println(responseJsonData);
            return responseJsonData;
        } catch (Exception e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        }finally {
            if (!ObjectUtils.isEmpty(inputStream)){
                inputStream.close();
            }
        }
        return null;
    }


   
    /**
     * 插入 Api 相关数据
     *
     * @param sbApiData
     */
    private void insertApiInfo(SbApiData sbApiData) {
        String apiId = sbApiData.getId();
        // 获取请求头信息
        List<SbApiHeaderData> headerDataList = sbApiData.getHeaderDataList();
        insertHeaderData(apiId, headerDataList);

        List<SbApiPathVariableData> pathVariableDataList = sbApiData.getPathVariableDataList();
        insertPathVariableData(apiId, pathVariableDataList);

        // 获取 请求参数信息
        List<SbApiQueryData> queryDataList = sbApiData.getQueryDataList();
        insertQueryData(apiId, queryDataList);

        // 获取 请求体参数信息
        SbApiBodyData bodyData = sbApiData.getBodyData();
        insertBodyData(apiId, bodyData);
    }
    

    /**
     * 删除 ApiData关联的数据
     *
     * @param apiId
     */
    private void deleteApi(String apiId) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("api_id", apiId);
        headerDataMapper.deleteByMap(paramMap);
        queryDataMapper.deleteByMap(paramMap);
        pathVariableDataMapper.deleteByMap(paramMap);

        // 删除 Body参数中 Kv
        List<SbApiBodyData> sbApiBodyDataList = bodyDataMapper.selectByMap(paramMap);
        if (!CollectionUtils.isEmpty(sbApiBodyDataList)) {
            sbApiBodyDataList.forEach(v -> {
                QueryWrapper<SbApiBodyKvData> apiBodyKvDataQueryWrapper = new QueryWrapper<>();
                apiBodyKvDataQueryWrapper.eq("body_id", v.getId());
                bodyKvDataMapper.delete(apiBodyKvDataQueryWrapper);
            });
        }
        bodyDataMapper.deleteByMap(paramMap);
    }

    /**
     * 新增 请求路径参数
     * @param apiId
     * @param insertPathVariableData
     */
    private void insertPathVariableData(String apiId, List<SbApiPathVariableData> insertPathVariableData) {
        if (!CollectionUtils.isEmpty(insertPathVariableData)) {
            insertPathVariableData.forEach(v -> {
                // 重置ID
                v.setId(null);
                v.setApiId(apiId);
                pathVariableDataMapper.insert(v);
            });
        }
    }

    /**
     * 新增请求头
     *
     * @param apiId
     * @param headerDataList
     */
    private void insertHeaderData(String apiId, List<SbApiHeaderData> headerDataList) {
        if (!CollectionUtils.isEmpty(headerDataList)) {
            headerDataList.forEach(v -> {
                // 重置ID
                v.setId(null);
                v.setApiId(apiId);
                headerDataMapper.insert(v);
            });
        }
    }

    /**
     * 新增请求参数
     *
     * @param apiId
     * @param queryDataList
     */
    private void insertQueryData(String apiId, List<SbApiQueryData> queryDataList) {
        if (!CollectionUtils.isEmpty(queryDataList)) {
            queryDataList.forEach(v -> {
                // 重置ID
                v.setId(null);
                v.setApiId(apiId);
                queryDataMapper.insert(v);
            });
        }
    }


    /**
     * 新增请求题参数
     *
     * @param apiId
     * @param bodyData
     */
    private void insertBodyData(String apiId, SbApiBodyData bodyData) {
        if (!ObjectUtils.isEmpty(bodyData)) {
            // 重置ID
            bodyData.setId(null);
            bodyData.setApiId(apiId);
            bodyDataMapper.insert(bodyData);

            // 判断是否为kv
            int type = bodyData.getType();
            if (type == 2) {
                List<SbApiBodyKvData> bodyKvDataList = bodyData.getBodyKvDataList();
                if (!CollectionUtils.isEmpty(bodyKvDataList)) {
                    String bodyDataId = bodyData.getId();
                    bodyKvDataList.forEach(v -> {
                        // 重置ID
                        v.setId(null);
                        v.setBodyId(bodyDataId);
                        bodyKvDataMapper.insert(v);
                    });
                }
            }
        }
    }
}
